/**
 * Created by jinxs on 14-8-13.
 */
(function ($) {
    /**
     * 缓存名称
     * @type {string}
     * @private
     */
    var _cacheName = 'uiValidate';
    /**
     * @class 验证组件
     * @constructor uiValidate
     * @summary 构造函数
     * @param [options] {Object|String} 组件配置参数|要调用的组件方法名
     * @param [param] {Object} 表示要调用的组件方法的参数
     * @example
     *  //采用默认值
     * $('#tab').uiValidate();
     * //设置组件参数
     *  $('#tab').uiValidate({delay:'200',width:'150'});
     * //调用组件方法
     * $('#tab').uiValidate('destroy','');
     */
    $.fn.uiValidate = function (options, param) {
        if (this.length > 0 && typeof options == 'string') {
            return $.fn.uiValidate.methods[options](this, param);
        }
        return this.each(function () {
            var me = $(this);
            var state = me.data(_cacheName);

            options = options || {};
            if (state) {
                $.extend(state.options, options);
            } else {
                me.data(_cacheName, {options: $.extend({}, $.fn.uiValidate.defaults, me.parseUIConfig(), options)});
                _init(me);
            }
            _isValidate(me);
            _isValid(me);
            setTimeout(function () {
                _hideTip(me);
            }, options.delay);
            $.getByParentID(me.attr('id'), $.uiTemplate.uiValidate.lenDiv).hide();
        });
    };
    /**
     * 方法
     * @lends uiValidate.prototype
     */
    $.fn.uiValidate.methods = {
        /**
         * @summary 获取组件配置参数
         * @function
         * @name uiValidate#options
         * @returns {Object}
         * @example
         *  $('#btn').uiValidate('options');
         */
        options: function (target) {
            return $.data(target[0], _cacheName).options;
        },
        /**
         * @summary 移除组件
         * @name uiValidate#destroy
         * @function
         * @returns {jQuery} 组件对象
         */
        destroy: function (target) {
            _destroy(target);
        },
        /**
         * @summary 验证
         * @name uiValidate#validate
         * @function
         * @returns {jQuery} 组件对象
         */
        validate: function (target) {
            _isValid(target);
            return target;
        },
        /**
         * @summary 是否合法
         * @name uiValidate#isValid
         * @function
         * @returns {Boolean}
         */
        isValid: function (target) {
            return _isValid(target);
        },
        /**
         * @summary 启用验证功能
         * @name uiValidate#enableValidation
         * @function
         * @returns {jQuery} 组件对象
         */
        enableValidation: function (target) {
            _isValidate(target, false);
            return target;
        },
        /**
         * @summary 禁用验证功能
         * @name uiValidate#disableValidation
         * @function
         * @returns {jQuery} 组件对象
         */
        disableValidation: function (target) {
            _isValidate(target, true);
            return target;
        },
        /**
         * @summary 启用组件
         * @name uiValidate#enable
         * @function
         * @returns {jQuery} 组件对象
         */
        enable: function (target) {
            target.attr('readonly', false).removeClass('ui_validate_disabled');
            _isValidate(target, false);
            return target;
        },
        /**
         * @summary 禁用组件
         * @name uiValidate#disable
         * @function
         * @returns {jQuery} 组件对象
         */
        disable: function (target) {
            _isValidate(target, true);
            return target;
        },
        /**
         * @summary 设置组件是否为只读
         * @name uiValidate#setReadonly
         * @function
         * @param readonly {Boolean} 是否为只读
         * @returns {jQuery} 组件对象
         */
        setReadonly: function (target, readonly) {
            _setReadonly(target, readonly);
            return target;
        }
    };
    /**
     * 默认配置
     * @lends uiValidate.prototype
     */
    $.fn.uiValidate.defaults = {
        /**
         * @type Number
         * @default 150
         * @summary 组件宽度
         */
        width: 150,
        /**
         * @type Boolean
         * @default false
         * @summary 是否必填
         */
        required: false,
        star: {show: true, front: false},
        /**
         * @type Boolean
         * @default false
         * @summary 指示组件是否禁用
         */
        disabled: false,
        readonly: false,
        /**
         * @type String
         * @default null
         * @summary 空值
         */
        nullValue: null,
        /**
         * 验证规则包含：<br/><br/>
         * <TABLE cellSpacing="1" width="100%" class="params">
         * <TR>
         * <TH width="12%">属性</TH>
         * <TH width="88%">说明</TH></TR>
         * <TR><TD align=center>username</TD><TD>姓名</TD></TR>
         * <TR><TD align=center>phone</TD><TD>电话</TD></TR>
         * <TR><TD align=center>mobile</TD><TD>移动电话</TD></TR>
         * <TR><TD align=center>email</TD><TD>邮箱</TD></TR>
         * <TR><TD align=center>url</TD><TD>URL</TD></TR>
         * <TR><TD align=center>length</TD><TD>输入文本的长度:用法：length[0,10]</TD></TR>
         * <TR><TD align=center>remote</TD><TD>远程</TD></TR>
         * </TABLE>
         * @type String
         * @default null
         * @summary 验证类型
         */
        validType: null,
        /**
         * @type String
         * @default null
         * @summary 验证参数
         */
        validParams: null,
        /**
         * @type Boolean
         * @default false
         * @summary 是否输入完即验证
         */
        tipAfterInput: false,
        /**
         * @type Boolean
         * @default false
         * @summary 是否以html Title的形式显示提示信息
         */
        showTitleTip: false,
        /**
         * @type Number
         * @default 200
         * @summary 组件输入框在编辑后执行验证前的延迟毫秒数
         */
        delay: 200,
        /**
         * @type String
         * @default 必填项！
         * @summary 必填提示消息
         */
        missingMessage: '必填项！',
        tipMessage:'',
        /**
         * @type String
         * @default ""
         * @summary 无效提示消息
         */
        invalidMessage: '',
        /**
         * @type String
         * @default right
         * @summary 提示消息的位置
         */
        tipPosition: 'right',
        /**
         * @type String
         * @default  [0, 19]
         * @summary 提示消息的偏移量
         */
        tipOffset: [0, 0],
        /**
         * @type Boolean
         * @default false
         * @summary 是否显示验证后的效果
         */
        novalidate: false,
        /**
         * @summary 在验证之后触发的方法。
         * @event
         * @name uiValidate#afterValidate
         * @param isValidate {Boolean} 是否验证
         * @default emptyFn
         */
        afterValidate: function (isValidate) {
        },
        /**
         * 验证规则包含：<br/><br/>
         * <TABLE cellSpacing="1" width="100%" class="params">
         * <TR>
         * <TH width="12%">属性</TH>
         * <TH width="88%">说明</TH></TR>
         * <TR><TD align=center>username</TD><TD>姓名</TD></TR>
         * <TR><TD align=center>phone</TD><TD>电话</TD></TR>
         * <TR><TD align=center>mobile</TD><TD>移动电话</TD></TR>
         * <TR><TD align=center>email</TD><TD>邮箱</TD></TR>
         * <TR><TD align=center>url</TD><TD>URL</TD></TR>
         * <TR><TD align=center>length</TD><TD>输入文本的长度</TD></TR>
         * <TR><TD align=center>remote</TD><TD>远程</TD></TR>
         * </TABLE>
         * @summary 验证规则定义，通过validType调用，可通过扩展该方法实现更多的验证规则
         * @name uiValidate#rules
         */
        rules: {
            username: {
                validator: function (val) {
                    return $.regexs.username.test(val);
                }, message: '请输入合法的用户名！'
            },
            phone: {
                validator: function (val) {
                    return $.regexs.phone.test(val);
                }, message: '电话格式错误！'
            },
            mobile: {
                validator: function (val) {
                    return $.regexs.mobile.test(val);
                }, message: '手机号码格式错误！'
            },
            email: {
                validator: function (val) {
                    return $.regexs.email.test(val);
                }, message: "请输入有效的邮箱地址！"
            },
            url: {
                validator: function (val) {
                    return $.regexs.url.test(val);
                }, message: "请输入合法的URL！"
            },
            length: {
                validator: function (val, len) {
                    var valLen = $.trim(val).length;
                    var lenDivName = $.uiTemplate.uiValidate.lenDiv;
                    var lenDiv = $.getByParentID(this[0].id, lenDivName);
                    if (lenDiv.length == 0) {
                        lenDiv = $('<div id="' + $.getIDByParentID(this[0].id, lenDivName) + '" class="ui_validate_len"></div>');
                        this.after(lenDiv);
                    }
                    lenDiv.html('字数：' + valLen);
                    if (_IEunder9) {
                        lenDiv.width(80);
                    }
                    var pos = this.position();
                    lenDiv.css({
                        top: pos.top + this.outerHeight(),
                        left: pos.left + this.outerWidth() - lenDiv.outerWidth()
                    });
                    return valLen >= len[0] && valLen <= len[1];
                }, message: "长度必须介于{0}~{1}。"
            },
            remote: {
                validator: function (val, params) {
                    var date = {};
                    date[params[1]] = val;
                    var responseText = $.ajax({
                        url: params[0],
                        dataType: "json",
                        data: date,
                        async: false,
                        cache: false,
                        type: "post"
                    }).responseText;
                    return responseText == "true";
                }, message: "请确认信息的正确性！"
            }
        }
    };
    var _init = function (target) {
        target.each(function () {
            var me = $(this);
            if (this.style.width == '' && me.attr("cols") === undefined) {
                me.width(me.data(_cacheName).options.width);
            }
            me.setElemID();
            me.addClass("ui_validate");
        });
    };

    var _destroy = function (target) {
        target.each(function () {
            var me = $(this);
            var state = me.data(_cacheName);
            state.validating = false;
            if (state.timer) {
                clearTimeout(state.timer);
            }
            me.tooltip("destroy");
            me.remove();
        });
    };

    function _bindEvents(target) {
        var state = $.data(target[0], _cacheName);
        var options = state.options;
        target.unbind(".uiValidate");
        if (options.novalidate) {
            return;
        }
        target.bind("focus.uiValidate", function () {
            state.validating = true;
            state.value = undefined;
            target.addClass('ui-focus');
            if (options.tipAfterInput) {
                (function () {
                    if (state.validating) {
                        if (state.value != target.val()) {
                            state.value = target.val();
                            if (state.timer) {
                                clearTimeout(state.timer);
                            }
                            state.timer = setTimeout(function () {
                                vali();
                            }, state.options.delay);
                        } else {
                            _reShowTip(target);
                        }
                        setTimeout(arguments.callee, 200); //递归调用
                    }
                })();
            } else {
                vali();
            }

            function vali() {
                var vali = target.uiValidate("isValid");
            }

            var lenDiv = $.getByParentID(target[0].id, $.uiTemplate.uiValidate.lenDiv);
            lenDiv.show();
        })
            .bind("blur.uiValidate", function () {
                target.removeClass('ui-focus');
                if (state.timer) {
                    clearTimeout(state.timer);
                    state.timer = undefined;
                }
                state.validating = false;
                if (!options.tipAfterInput) {
                    target.uiValidate("validate");
                }
                _hideTip(target);
                var lenDiv = $.getByParentID(target[0].id, $.uiTemplate.uiValidate.lenDiv);
                lenDiv.hide();
            })
            .bind("mouseover.uiValidate", function () {
                if(options.tipMessage!=''){
                    state.message=options.tipMessage;
                    _showTip(target);
                }
                if (target.hasClass("ui_validate-invalid")) {
                    _showTip(target);
                }
            })
            .bind("mouseleave.uiValidate", function () {
                if (!state.validating) {
                    _hideTip(target);
                }
            });
    };
    var _showTip = function (target) {
        target.each(function () {
            var me = $(this);
            var state = me.data(_cacheName);
            var options = state.options;
            if (_IEunder6 || options.showTitleTip) {
                me[0].title = state.message;
                state.tip = true;
                return;
            }
            me.uiTooltip({content: state.message, region: options.tipPosition, offset: options.tipOffset})
                .uiTooltip('show');
            state.tip = true;
        });
    };

    var _reShowTip = function (target) {
        var state = $.data(target[0], _cacheName);
        if (state) {
            if (_IEunder6 || state.options.showTitleTip) {
                target[0].title = state.message;
                return;
            }
            if (state.tip) {
                var targetID = target.getElemID();
                var tipContent = $.getByParentID(targetID, $.uiTemplate.tooltip.content);
                if (tipContent.length > 0 && tipContent.is(':visible')) {
                    tipContent.html(state.message);
                }
            }
        }
    };
    var _hideTip = function (target) {
        target.each(function () {
            var me = $(this);
            var state = me.data(_cacheName);
            if (_IEunder6 || state.options.showTitleTip) {
                return;
            }
            state.tip = false;
            me.uiTooltip('hide');
        });
    };

    var _isValid = function (target) {
        var rs = true;
        target.each(function () {
            var me = $(this);
            var state = me.data(_cacheName);
            var options = state.options;
            var val = me.val();
            if (options.novalidate || me.is(":disabled")) {
                me.removeClass("ui_validate-invalid");
                _hideTip(me);
                me[0].title = '';
                return true;
            }
            if (options.required) {
                me[0].title = '';
                if ($.trim(val) == "" || val == options.nullValue) {
                    me.addClass("ui_validate-invalid");
                    _setMsg(options.missingMessage);
                    if (state.validating) {
                        _showTip(me);
                    }
                    options.afterValidate.call(me, false);
                    rs = false;
                    return true;
                }
                options.afterValidate.call(me, true);
            }
            if (options.validType) {
                if ($.isArray(options.validType)) {
                    for (var i = 0; i < options.validType.length; i++) {
                        if (!_valid(options.validType[i])) {
                            options.afterValidate.call(me, false);
                            rs = false;
                            return true;
                        }
                    }
                } else {
                    if (typeof options.validType == "string") {
                        if (!_valid(options.validType)) {
                            options.afterValidate.call(me, false);
                            rs = false;
                            return true;
                        }
                    } else {
                        for (var typeName in options.validType) {
                            var valid = options.validType[typeName];
                            if (!_valid(typeName, valid)) {
                                options.afterValidate.call(me, false);
                                rs = false;
                                return true;
                            }
                        }
                    }
                }
            }
            me.removeClass("ui_validate-invalid");
            _hideTip(me);
            options.afterValidate.call(me, true);

            function _setMsg(msg) {
                state.message = msg;
            }

            function _valid(typeName, validOpts) {
                me[0].title = '';
                var params = /([a-zA-Z_]+)(.*)/.exec(typeName);
                var rule = options.rules[params[1]];
                if (rule && val) {
                    var valid_options = validOpts || options.validParams || eval(params[2]);
                    if (!rule["validator"].call(me, val, valid_options)) {
                        me.addClass("ui_validate-invalid");
                        var msg = rule["message"];
                        if (valid_options) {
                            for (var i = 0; i < valid_options.length; i++) {
                                msg = msg.replace(new RegExp("\\{" + i + "\\}", "g"), valid_options[i]);
                            }
                        }
                        _setMsg(options.invalidMessage || msg);
                        if (state.validating) {
                            _showTip(me);
                        }
                        return false;
                    }
                }
                return true;
            }
        });
        return rs;
    };

    var _isValidate = function (target, novalidate) {
        target.each(function () {
            var me = $(this);
            if (me.data(_cacheName)) {
                var options = me.data(_cacheName).options;
                if (novalidate != undefined) {
                    options.novalidate = novalidate;
                }
                var starId = me.attr('id') + '-star';
                if (options.novalidate) {
                    me.removeClass("ui_validate-invalid");
                    _hideTip(me);
                    if (options.star.show) {
                        $('#' + starId).remove();
                    }
                } else {
                    if (options.star.show && options.required && !options.readonly) {
                        var star = '<span id="' + starId + '" class="ui_inputStar">*</span>';
                        var tar = me;
                        if (tar.hasClass('ui_combo-text') || tar.hasClass('ui_date') || tar.hasClass('ui_ueditor')) {
                            tar = me.parent();
                            addStar();
                        }else{
                            if(!me.attr("readonly")){
                                addStar();
                            }
                        }
                        function  addStar() {
                            if ($('#' + starId).length == 0) {
                                if (options.star.front) {
                                    tar.before(star);
                                } else {
                                    tar.after(star);
                                }
                            }
                        }
                    } else {
                        $('#' + starId).remove();
                    }
                }
                _bindEvents(me);
            }
        });
    };
    var _setReadonly = function (target, readonly) {
        target.each(function () {
            var me = $(this);
            if (me.data(_cacheName)) {
                var options = me.data(_cacheName).options;
                options.readonly=readonly == undefined ? false : readonly;
            }
        });
        _isValidate(target, readonly);
        if (readonly) {
            target.attr('readonly', true).addClass('ui_validate_disabled');
        } else {
            target.attr('readonly', false).removeClass('ui_validate_disabled');
        }
    }
})(jQuery);
